#pragma once

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <semaphore.h>

const size_t num = 5;

class semaphore
{
public:
    semaphore(int value) { sem_init(&sem, 0, value); }
    ~semaphore() { sem_destroy(&sem); }

    void wait() { sem_wait(&sem); }
    void post() { sem_post(&sem); }
    
private:
    sem_t sem;
};

template<class T>
class loop_queue
{
public:
    loop_queue(int size = num) : _pdr_sem(size), _csr_sem(0)
    {}

    ~loop_queue()
    {}

    void push(const T& data)
    {
        _pdr_sem.wait();
        {
            std::unique_lock<std::mutex> lock(_p_mtx);
            _q.push_back(data);
        }
        _csr_sem.post();
    }

    void pop(T* data)
    {
        _csr_sem.wait();
        {
            std::unique_lock<std::mutex> lock(_c_mtx);
            *data = _q.back();
            _q.pop_back();
        }
        _pdr_sem.post();
    }

private:
    std::vector<T> _q;

    std::mutex _p_mtx;
    std::mutex _c_mtx;
    semaphore _csr_sem;
    semaphore _pdr_sem;
};

